﻿using DesertKharonIrcPlugin.Emotes.Twitch;
using DesertKharonIrcPlugin.GdiPlusRendering;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;

namespace DesertKharonIrcPlugin.Emotes
{
    public class EmoteManager : IDisposable
    {
        private class KeyOccurance
        {
            public int Index { get; set; }
            public string Key { get; set; }
        }

        private LoadingAnimation _loadingAnimation;
        private string _destinationFolder;
        private TimeSpan _timeToEmoteUpdate = TimeSpan.FromDays(7d);
        private Dictionary<string, Emote> _emoteDict;
        private List<string> _keyList;

        public EmoteManager(string destinationFolder, float scale)
        {
            _destinationFolder = destinationFolder;

            _emoteDict = new Dictionary<string, Emote>();
            _loadingAnimation = new LoadingAnimation(scale);
        }

        public EmoteManager(string destinationFolder, float scale, List<TwitchEmote> twitchEmoteList)
        {
            _destinationFolder = destinationFolder;

            _loadingAnimation = new LoadingAnimation(scale);
            List<Emote> emoteList = twitchEmoteList
                .GroupBy(g => g.Name)
                .Select(e => e.First())
                .GroupBy(g => g.Url)
                .Select(g => new Emote(g.Select(e => e.Name).ToList(), new Uri(g.Key), _destinationFolder, scale))
                .ToList();

            _emoteDict = new Dictionary<string, Emote>();
            foreach (var emote in emoteList)
            {
                emote.LoadingAnimation = _loadingAnimation;
                foreach (var key in emote.KeyList)
                {
                    if (_emoteDict.ContainsKey(key) == false)
                        _emoteDict.Add(key, emote);
                }
            }

            _keyList = _emoteDict.Keys.ToList();
            _keyList.Add(" ");
        }

        public Emote GetEmote(string key)
        {
            Emote emote;
            if (_emoteDict.TryGetValue(key, out emote))
            {
                if (!emote.IsLoaded && !emote.IsLoading)
                    emote.Load();

                return emote;
            }

            return null;
        }

        public List<string> SplitMessage(string message, StringSplitOptions stringSplitOptions)
        {
            List<string> resultList = new List<string>();

            if (!String.IsNullOrWhiteSpace(message))
            {
                Dictionary<int, string> indexKeyDict = _keyList
                    .SelectMany(key =>
                    {
                        List<KeyOccurance> allOccurances = new List<KeyOccurance>();

                        int index = message.IndexOf(key);
                        while (index > -1)
                        {
                            allOccurances.Add(new KeyOccurance
                            {
                                Index = index,
                                Key = key
                            });

                            if (index < message.Length - 1)
                                index = message.IndexOf(key, index + 1);
                            else
                                index = -1;
                        }

                        return allOccurances;
                    })
                    .GroupBy(g => g.Index)
                    .Select(e => e.OrderByDescending(o => o.Key.Length).First())
                    .ToDictionary(key => key.Index, value => value.Key);

                if (indexKeyDict != null && indexKeyDict.Count > 0)
                {
                    int startIndex = 0;
                    int currentIndex = 0;
                    while (currentIndex < message.Length)
                    {
                        string value;
                        if (indexKeyDict.TryGetValue(currentIndex, out value))
                        {
                            if (currentIndex > startIndex)
                            {
                                resultList.Add(message.Substring(startIndex, currentIndex - startIndex));
                                startIndex = currentIndex;
                            }

                            if (currentIndex == startIndex)
                            {
                                resultList.Add(value);
                                currentIndex += value.Length;
                                startIndex = currentIndex;
                            }
                        }
                        else
                        {
                            currentIndex += 1;
                            if (currentIndex == message.Length)
                                resultList.Add(message.Substring(startIndex, currentIndex - startIndex));
                        }
                    }
                }
                else
                    resultList.Add(message);
            }

            if (stringSplitOptions == StringSplitOptions.RemoveEmptyEntries)
                return resultList.Where(e => !String.IsNullOrWhiteSpace(e)).ToList();

            return resultList;
        }

        public void Update(float elapsedSeconds)
        {
            if (_loadingAnimation != null)
                _loadingAnimation.Update(elapsedSeconds);
        }

        public void Dispose()
        {
            if (_emoteDict != null)
            {
                foreach (var kvp in _emoteDict)
                {
                    kvp.Value.Dispose();
                }

                _emoteDict.Clear();
                _emoteDict = null;
            }

            if (_loadingAnimation != null)
            {
                _loadingAnimation.Dispose();
                _loadingAnimation = null;
            }
        }
    }
}
